﻿// Inner Fire 游戏引擎库
// ConfigManager - 配置管理器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：框架层(5)
// 和Assets一样，通过Xml载入的配置文件。和Assets分管不同的资源。
// Assets管理的是需要后载入的东西，比如贴图，模型。这些不可能都在游戏开始载入。
// 但ConfigManager则是载入一切需要的配置。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-07-05

#pragma once

#include <EASTL/string_view.h>
#include <EASTL/vector.h>
#include <game/animation/avatar.h>
#include <game/animation/avatar_id.h>
#include <game/config/config_info.h>
#include <game/config/prefab.h>
#include <game/config/ui_prefab.h>
#include <game/controller/chara_animation.h>
#include <game/controller/attack_info.h>
#include <game/map/map_setting.h>
#include <game/map/scene_info.h>
#include <game/physics/physics_bone_setting.h>
#include <game/physics/collider_info.h>
#include <game/physics/layer_setting.h>
#include <ref_info.h>
#include <xml_reader.h>

namespace ifire::game {
class GameManager;

class ConfigManager {
public:
  ConfigManager(GameManager* gm, const ikit::XmlNode& root);
  ConfigManager(const ConfigManager& lhs) = delete;
  ConfigManager& operator=(const ConfigManager& lhs) = delete;
  ~ConfigManager();

  // 用于Singleton模式
  static ConfigManager& GetInstance() { return *instance_; }

  // 进行配置的设置
  void Setup();

  // 通过一个MapSetting文件载入
  void LoadMapSettings(const eastl::string_view& filename);
  // 通过一个PhysicsBoneSetting文件载入
  void LoadPhysicsBoneSettings(const eastl::string_view& filename);
  // 通过一个AvatarGroup文件载入
  void LoadAvatarGroups(const eastl::string_view& filename);
  // 通过一个Prefab文件载入
  void LoadPrefabs(const eastl::string_view& filename);
  // 通过一个UIPrefab文件载入
  void LoadUIPrefabs(const eastl::string_view& filename);
  // 通过一个Avatar文件载入
  void LoadAvatars(const eastl::string_view& filename);
  // 通过一个CharaAnimation文件载入
  void LoadCharaAnimations(const eastl::string_view& filename);
  // 通过一个SceneInfo文件载入
  void LoadScenes(const eastl::string_view& filename);
  // 通过一个AttackInfo文件载入
  void LoadAttacks(const eastl::string_view& filename);
  // 通过一个Collider文件载入
  void LoadColliders(const eastl::string_view& filename);
  // 通过一个LayerSetting文件载入
  void LoadLayerSettings(const eastl::string_view& filename);

  // 获得一个地图设置
  MapSetting* GetMapSetting(ikit::sstr name);
  // 获得一个动态骨骼设置
  PhysicsBoneSetting* GetPhysicsBoneSetting(ikit::sstr name);
  // 获得一个动态骨骼设置
  AvatarGroup* GetAvatarGroup(ikit::sstr name);
  // 获得一个Prefab
  Prefab* GetPrefab(ikit::sstr name);
  // 获得一个UIPrefab
  UIPrefab* GetUIPrefab(ikit::sstr name);
  // 获得一个Avatar
  Avatar* GetAvatar(ikit::sstr name);
  // 获得一个CharaAnimation
  CharaAnimation* GetCharaAnimation(ikit::sstr name);
  // 获得一个SceneInfo
  SceneInfo* GetScene(ikit::sstr name);
  // 获得一个Attack
  AttackInfo* GetAttack(ikit::sstr name);
  // 获得一个Collider
  ColliderInfo* GetCollider(ikit::sstr name);
  // 获得一个LayerSetting
  LayerSetting* GetLayerSetting(ikit::sstr name);

  eastl::vector<MapSettingPtr>& MapSettings() { return map_settings_; }
  eastl::vector<PBonePtr>& PhysicsBoneSettings() { return physics_settings_; }
  eastl::vector<AvatarGroupPtr>& AvatarGroups() { return avatar_groups_; }
  eastl::vector<PrefabPtr>& Prefabs() { return prefabs_; }
  eastl::vector<UIPrefabPtr>& UIPrefabs() { return ui_prefabs_; }
  eastl::vector<AvatarPtr>& Avatars() { return avatars_; }
  eastl::vector<CAnimPtr>& CharaAnimations() { return chara_animations_; }
  eastl::vector<SceneInfoPtr>& Scenes() { return scenes_; }
  eastl::vector<AttackInfoPtr>& Attacks() { return attacks_; }
  eastl::vector<ColliderInfoPtr>& Colliders() { return colliders_; }
  eastl::vector<LayerSettingPtr>& LayerSettings() { return layers_; }

  // 用于模板的快捷方式
  static void Setup(ikit::rinfo<MapSetting>& info) {
    info.set(instance_->GetMapSetting(info.name));
  }
  static void Setup(ikit::rinfo<PhysicsBoneSetting>& info) {
    info.set(instance_->GetPhysicsBoneSetting(info.name));
  }
  static void Setup(ikit::rinfo<AvatarGroup>& info) {
    info.set(instance_->GetAvatarGroup(info.name));
  }
  static void Setup(ikit::rinfo<Prefab>& info) {
    info.set(instance_->GetPrefab(info.name));
  }
  static void Setup(ikit::rinfo<UIPrefab>& info) {
    info.set(instance_->GetUIPrefab(info.name));
  }
  static void Setup(ikit::rinfo<Avatar>& info) {
    info.set(instance_->GetAvatar(info.name));
  }
  static void Setup(ikit::rinfo<CharaAnimation>& info) {
    info.set(instance_->GetCharaAnimation(info.name));
  }
  static void Setup(ikit::rinfo<SceneInfo>& info) {
    info.set(instance_->GetScene(info.name));
  }
  static void Setup(ikit::rinfo<AttackInfo>& info) {
    info.set(instance_->GetAttack(info.name));
  }
  static void Setup(ikit::rinfo<ColliderInfo>& info) {
    info.set(instance_->GetCollider(info.name));
  }
  static void Setup(ikit::rinfo<LayerSetting>& info) {
    info.set(instance_->GetLayerSetting(info.name));
  }

  // 得到默认的层
  LayerSetting* GetDefaultLayers() { return default_layers_; }
  // 从默认的值获得一个ID（这里直接使用Singleton的快捷方式）
  static int GetLayer(ikit::sstr name);
  // 从默认的值获得一个Mask（这里直接使用Singleton的快捷方式）
  static uint64_t GetMask(ikit::sstr name);

private:
  // 对于父级GM的引用。
  GameManager* gm_;
  // 用于Singleton模式
  static ConfigManager* instance_;

  // 地图设置
  eastl::vector<MapSettingPtr> map_settings_;
  // 动态骨骼设置
  eastl::vector<PhysicsBoneSettingPtr> physics_settings_;
  // Avatar配置
  eastl::vector<AvatarGroupPtr> avatar_groups_;
  // 预置体
  eastl::vector<PrefabPtr> prefabs_;
  // UI预置体
  eastl::vector<UIPrefabPtr> ui_prefabs_;
  // 通用骨架
  eastl::vector<AvatarPtr> avatars_;
  // 角色动画配装
  eastl::vector<CharaAnimationPtr> chara_animations_;
  // 场景配置
  eastl::vector<SceneInfoPtr> scenes_;
  // 攻击配置
  eastl::vector<AttackInfoPtr> attacks_;
  // 碰撞体配置
  eastl::vector<ColliderInfoPtr> colliders_;
  // 碰撞体的层配置
  eastl::vector<LayerSettingPtr> layers_;

  // 必然拥有的Humanoid，访问的快捷方式
  AvatarGroup* humanoid_;
  // 特殊处理，默认的层
  LayerSetting* default_layers_;

  // 通过模板载入
  template <typename T>
  void LoadFile(const eastl::string_view& filename, const char* nodeName,
      eastl::vector<std::unique_ptr<T>>& container) {
    if (filename.empty()) return;

    XmlReader xml(filename.data());
    xml.Root().Foreach(nodeName, [this, &container](XmlNode& node, int index) {
      auto item = std::make_unique<T>(this, node);
      container.push_back(std::move(item));
    });
  }
};

} // namespace ifire::game